﻿using NUnit.Framework;
using ValidationFramework.Reflection;
using ValidationFramework.Tests.TestHelpers;
using System;

namespace ValidationFramework.Tests.Reflection
{
	public class PropertyInfoExtensionTest
	{
		[TestFixture]
		public class IsHidingMemeber
		{
			#region Test Model

			public class ChildClass : BaseClass
			{
				public new virtual string ExplicitHideProperty { get; set; }
				public override string OverrideProperty { get; set; }
				public string ImplicitHideProperty { get; set; }
			}

			public class BaseClass
			{
				public virtual string ExplicitHideProperty { get; set; }
				public virtual string OverrideProperty { get; set; }
				public string ImplicitHideProperty { get; set; }
			}

			#endregion

			// TODO: This needs to be tested in VB as well since VB handles hiding differently
			[Test]
			public void Should_Return_True_When_Current_Property_Info_Is__Explicitly_Hiding_Base_Member()
			{
				Assert.IsFalse(typeof(BaseClass).GetProperty("ExplicitHideProperty").IsHidingMember());
				Assert.IsTrue(typeof(ChildClass).GetProperty("ExplicitHideProperty").IsHidingMember());
			}
			[Test]
			public void Should_Return_True_When_Current_Property_Info_Is_Implicitly_Hiding_Base_Member()
			{
				Assert.IsTrue(typeof(ChildClass).GetProperty("ImplicitHideProperty").IsHidingMember());
				Assert.IsFalse(typeof(BaseClass).GetProperty("ImplicitHideProperty").IsHidingMember());
			}
			[Test]
			public void Should_Return_False_When_Current_Property_Info_Is_Overriding_Base_Member()
			{

				Assert.IsFalse(typeof(ChildClass).GetProperty("OverrideProperty").IsHidingMember());
				Assert.IsFalse(typeof(BaseClass).GetProperty("OverrideProperty").IsHidingMember());
			}

		}
		[TestFixture]
		public class IsExplcitProperty
		{
			#region Test Model

			public class ExplicitImplmentor : IChildInterface
			{
				int IChildInterface.ReadWriteProperty { get; set; }

				int IChildInterface.WriteOnlyProperty
				{
					set
					{
						var test = value;
					}
				}

				int IChildInterface.ReadOnlyProperty
				{
					get
					{
						return 0;
					}
				}

				int IChildInterface.ParentInterfaceProperty { get; set; }

				int IParentInterface.ParentInterfaceProperty { get; set; }
			}

			public class ImplicitImplementor : IChildInterface
			{
				public int ReadWriteProperty { get; set; }

				public int ReadOnlyProperty { get; set; }

				public int WriteOnlyProperty { get; set; }

				public int ParentInterfaceProperty { get; set; }
			}

			public interface IChildInterface : IParentInterface
			{
				int ReadWriteProperty { get; set; }

				int ReadOnlyProperty { get; }

				int WriteOnlyProperty { set; }

				int ParentInterfaceProperty { get; set; }
			}

			public interface IParentInterface
			{
				int ParentInterfaceProperty { get; set; }
			}

			public interface IUnrelatedInterface
			{
				int UnrelatedProperty { get; set; }
			}
			#endregion

			[Test]
			public void Should_Return_False_When_Child_Interface_Is_Tested_Against_Parent_Interface()
			{
				Assert.IsFalse(typeof(IChildInterface).GetProperty("ReadWriteProperty").IsExplicitPropertyOf(typeof(IParentInterface)));
			}
			[Test]
			public void Should_Return_True_When_Property_Explicitly_Implmements_An_Interface()
			{
				Assert.IsTrue(typeof(ExplicitImplmentor).GetProperty("ReadWriteProperty").IsExplicitPropertyOf(typeof(IChildInterface)));
				Assert.IsTrue(typeof(ExplicitImplmentor).GetProperty("WriteOnlyProperty").IsExplicitPropertyOf(typeof(IChildInterface)));
				Assert.IsTrue(typeof(ExplicitImplmentor).GetProperty("ReadOnlyProperty").IsExplicitPropertyOf(typeof(IChildInterface)));
				Assert.IsTrue(typeof(ExplicitImplmentor).GetProperty("ParentInterfaceProperty").IsExplicitPropertyOf(typeof(IChildInterface)));
				Assert.IsTrue(typeof(ExplicitImplmentor).GetProperty("ParentInterfaceProperty").IsExplicitPropertyOf(typeof(IParentInterface)));
			}
			[Test]
			public void Should_Return_False_When_Property_Implicitly_Implements_An_Interface()
			{
				Assert.IsFalse(typeof(ImplicitImplementor).GetProperty("ReadWriteProperty").IsExplicitPropertyOf(typeof(IChildInterface)));
				Assert.IsFalse(typeof(ImplicitImplementor).GetProperty("WriteOnlyProperty").IsExplicitPropertyOf(typeof(IChildInterface)));
				Assert.IsFalse(typeof(ImplicitImplementor).GetProperty("ReadOnlyProperty").IsExplicitPropertyOf(typeof(IChildInterface)));
				Assert.IsFalse(typeof(ImplicitImplementor).GetProperty("ParentInterfaceProperty").IsExplicitPropertyOf(typeof(IParentInterface)));
			}
			[Test]
			public void Should_Return_False_When_Type_Not_Implementing_Property()
			{
				Assert.IsFalse(typeof(ExplicitImplmentor).GetProperty("NotARealProperty").IsExplicitPropertyOf(typeof(IChildInterface)));
			}
			[Test]
			public void Should_Return_False_When_Type_Not_Implementing_Interface()
			{
				Assert.IsFalse(typeof(ImplicitImplementor).GetProperty("UnrelatedProperty").IsExplicitPropertyOf(typeof(IUnrelatedInterface)));
				Assert.IsFalse(typeof(ExplicitImplmentor).GetProperty("UnrelatedProperty").IsExplicitPropertyOf(typeof(IUnrelatedInterface)));
			}
		}

		[TestFixture]
		public class GetRuleAttributes
		{
			[TestFixture]
			public class Should_Work_For_Complex_Class
			{
			#region Test Model

			public class BottomClass : TempClass
			{

			}
			public class TempClass : Class, Interface1, Interface2
			{
				[AlwaysFail(Id = "3")]
				int Interface1.TempProperty
				{
					get;
					set;
				}

				[AlwaysFail(Id = "6")]
				int Interface2.TempProperty
				{
					get;
					set;
				}

				[AlwaysFail(Id = "5")]
				public override int TempProperty { get; set; }
			}

			public abstract class Class : Interface1
			{
				[AlwaysFail(Id = "4")]
				int Interface1.TempProperty { get; set; }

				[AlwaysFail(Id = "7")]
				public virtual int TempProperty { get; set; }
			}
			public interface Interface1
			{
				[AlwaysFail(Id = "0")]
				int TempProperty
				{
					get;
					set;
				}
			}
			public interface Interface2
			{
				[AlwaysFail(Id = "7")]
				int TempProperty
				{
					get;
					set;
				}
			}

			#endregion

			[Test]
			public void Test()
			{

				var attributes = typeof(BottomClass).GetProperty("TempProperty").GetRuleAttributes();

				Assert.AreEqual(1, typeof(Interface1).GetProperty("TempProperty").GetRuleAttributes().Count);
				Assert.AreEqual(1, typeof(Interface2).GetProperty("TempProperty").GetRuleAttributes().Count);
				Assert.AreEqual(2, typeof(Class).GetProperty("TempProperty").GetRuleAttributes().Count);
				Assert.AreEqual(3, typeof(TempClass).GetProperty("TempProperty").GetRuleAttributes().Count);
				Assert.AreEqual(3, typeof(BottomClass).GetProperty("TempProperty").GetRuleAttributes().Count);
			}
			}

			[TestFixture]
			public class Should_Ignore_Attr_Defined_On_Explicit_Properties
			{
				#region Test Model

				public class ClassWithExplicitProperty : Interface1
				{
					[AlwaysFail(Id = "0")]
					int Interface1.TempProperty { get; set; }
				}
				public interface Interface1
				{
					[AlwaysFail(Id = "0")]
					int TempProperty { get; set; }
				}
				#endregion

				[Test]
				public void Test()
				{
					Assert.AreEqual(0, typeof(ClassWithExplicitProperty).GetProperty("NonPublicProperty").GetRuleAttributes().Count);
				}

			}

			[TestFixture]
			public class Should_Get_Attr_From_Parent_Class
			{
				#region Test Model
				public class Parent
				{
					[AlwaysFail(Id = "0")]
					public string TestProperty { get; set; }
				}
				public class Child : Parent { }
				#endregion
				[Test]
				public void Test()
				{
					Assert.AreEqual(1, typeof(Child).GetProperty("TestProperty").GetRuleAttributes().Count);
				}
			}

			[TestFixture]
			public class Should_Ignore_Attr_Defined_On_NonPublic_Properties
			{
				#region Test Model

				public class ClassWithExplicitProperty : Interface1
				{
					#region Interface1 Members

					[AlwaysFail(Id = "0")]
					int Interface1.TempProperty
					{
						get;
						set;
					}

					#endregion

					[AlwaysFail(Id = "1")]
					public int TempProperty
					{
						get;
						set;
					}

					[AlwaysFail(Id = "2")]
					int NonPublicProperty
					{
						get;
						set;
					}
				}

				public interface Interface1
				{
					[AlwaysFail(Id = "0")]
					int TempProperty
					{
						get;
						set;
					}
				}
				#endregion

				[Test]
				public void Test()
				{
					Assert.AreEqual(0, typeof(ClassWithExplicitProperty).GetProperty("NonPublicProperty").GetRuleAttributes().Count);
				}

			}
		}
	}
}


